﻿// <copyright file="TypedAutofacBootStrapper.cs" company="SingularityShift.com">
// Copyright (c) 2011 SingularityShift.com. All rights reserved.
// </copyright>
// <author>Ben McClure</author>
// <email>ben@singularityshift.com</email>
// <date>3/26/2011</date>
// <summary>Implements the typed autofac boot strapper class</summary>
namespace FalloutModStudio
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;

    using Autofac;

    using Caliburn.Micro;

    using IContainer = Autofac.IContainer;

    /// <summary> Typed Autofac bootstrapper. </summary>
    /// <remarks> Ben McClure, 3/26/2011. </remarks>
    public class TypedAutofacBootstrapper<TRootViewModel> : Bootstrapper<TRootViewModel>
    {
        #region Fields

        protected readonly ILog _logger = LogManager.GetLog(typeof(TypedAutofacBootstrapper<>));

        protected IContainer _container;

        #endregion

        protected override void Configure()
        {
            var builder = new ContainerBuilder();

            // Register ViewModels
            builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray()).Where(
                type => type.Name.EndsWith("ViewModel")).Where(
                    type => !(string.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("ViewModels")).Where
                (type => type.GetInterface(typeof(INotifyPropertyChanged).Name) != null).AsSelf().InstancePerDependency(
                    );

            // Register Views
            builder.RegisterAssemblyTypes(AssemblySource.Instance.ToArray()).Where(type => type.Name.EndsWith("View")).
                Where(type => !(string.IsNullOrWhiteSpace(type.Namespace)) && type.Namespace.EndsWith("Views")).AsSelf()
                .InstancePerDependency();

            // Register a single window manager
            builder.Register<IWindowManager>(c => new WindowManager()).InstancePerLifetimeScope();

            // Register a single event aggregator
            builder.Register<IEventAggregator>(c => new EventAggregator()).InstancePerLifetimeScope();

            ConfigureContainer(builder);

            _container = builder.Build();
        }

        protected override object GetInstance(Type service, string key)
        {
            object instance;

            if (string.IsNullOrWhiteSpace(key))
            {
                if (this._container.TryResolve(service, out instance))
                {
                    return instance;
                }
            }
            else
            {
                if (this._container.TryResolveNamed(key, service, out instance))
                {
                    return instance;
                }
            }

            throw new Exception(string.Format("Could not locate any instances of contract {0}.", key ?? service.Name));
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return this._container.Resolve(typeof(IEnumerable<>).MakeGenericType(service)) as IEnumerable<object>;
        }

        protected override void BuildUp(object instance)
        {
            this._container.InjectProperties(instance);
        }

        protected virtual void ConfigureContainer(ContainerBuilder builder)
        {
        }
    }
}